#include "stdio.h"

/* **********************************************************************
*								 										*
*	putchar: This function is used to output a character.							*
*  																		*
*************************************************************************/
#define _CR_CRLF			1
#define _LINE_ECHO		1

void (*xfunc_out)(unsigned char);	/* Pointer to the output stream */
unsigned char (*xfunc_in)(void);	/* Pointer to the input stream */
static char *outptr;
/* **************************************************************
 *								*
 *	itoa: This function is used to transform data form. 	*
 *  								*
*************************************************************** */
static char itoa_buf[20]; 
char* itoa(int num, int base)
{
	char temp, *tbuf = itoa_buf;
	unsigned int n;
	int i, j, digit;

	for(i = 0; i < 20; i++)
		*(itoa_buf+i) = 0;
	
	/* If num is a negative number */
	if(num < 0 && base == 10)
	{
		itoa_buf[0] = '-';
		tbuf++;
		n = -num;	
	}
	
	n = num;
	for(i = 0; n > 0; i++)
	{
		/* If num is a hexadecimal number */
		if(base == 16)
		{
			digit = n % 16;
			n /= 16;
		}
		
		/* If num is a decimal number */
		if(base == 10)
		{
			digit = n % 10;
			n /= 10;
		}
		if(digit > 9) tbuf[i] = digit - 10 + 'a';
		else tbuf[i] = digit + '0';
	}
	
	tbuf[i] = 0;
	
	for(j = 0 ;j < i/2; j++)
	{
		temp = tbuf[j];
		tbuf[j] = tbuf[i - 1 - j];
		tbuf[i - 1 - j] = temp;
	}
	if(!num)
			tbuf[i++] = '0';
	tbuf[i] = 0;
	return &itoa_buf[0];
}



void putchar(const char ch)
{
	if (_CR_CRLF && ch == '\n') putchar('\r');		/* CR -> CRLF */

	DRV_RS232_Tx_Char((unsigned char)ch);	
}

/* **********************************************************************
 *									*
 *	puts: This function is used to output a character string.	*
 *  									*
*************************************************************************/
void puts(const unsigned char *string)
{ 
	const unsigned char *str = string;
	while(*str)
	{
		putchar(*str++);
	}
}


void fputs (					/* Put a string to the specified device */
	void(*func)(unsigned char),	/* Pointer to the output function */
	const char*	str				/* Pointer to the string */
)
{
	void (*pf)(unsigned char);


	pf = xfunc_out;		/* Save current output device */
	xfunc_out = func;	/* Switch output to specified device */
	while (*str)		/* Put the string */
		putchar(*str++);
	xfunc_out = pf;		/* Restore output device */
}

/* **********************************************************************
*																		*
*	getchar: This function is used to get a character.								*
*  																		*
*************************************************************************/

char getchar(void)
{
	char data = 0;
	
	DRV_RS232_Rx_Char((unsigned char *)&data);

	return data;
}

/* **********************************************************************
*									*
*	gets: This function is used to get a character string. 		*
*  									*
*************************************************************************/
int gets (		/* 0:End of stream, 1:A line arrived */
	char* buff,	/* Pointer to the buffer */
	int len		/* Buffer length */
)
{
#if 1
	int c, i;

	i = 0;
	for (;;) {
		c = getchar();				/* Get a char from the incoming stream */
		if (!c) return 0;			/* End of stream? */
		if (c == '\r') break;		/* End of line? */
		if (c == '\b' && i) {		/* Back space? */
			i--;
			//if (_LINE_ECHO) putchar(c);
			putchar('\b');
			putchar(' ');
			putchar('\b');
			continue;
		}
		if (c >= ' ' && i < len - 1) {	/* Visible chars */
			buff[i++] = c;
			if (_LINE_ECHO) putchar(c);
		}
	}
	buff[i] = 0;	/* Terminate with a \0 */
	if (_LINE_ECHO) putchar('\n');
	return 1;
#endif

}

int fgets (	/* 0:End of stream, 1:A line arrived */
	unsigned char (*func)(void),	/* Pointer to the input stream function */
	char* buff,	/* Pointer to the buffer */
	int len		/* Buffer length */
)
{
	unsigned char (*pf)(void);
	int n;


	pf = xfunc_in;			/* Save current input device */
	xfunc_in = func;		/* Switch input to specified device */
	n = gets(buff, len);	/* Get a line */
	xfunc_in = pf;			/* Restore input device */

	return n;
}



/*----------------------------------------------*/
/* Formatted string output                      */
/*----------------------------------------------*/
/*  xprintf("%d", 1234);			"1234"
    xprintf("%6d,%3d%%", -200, 5);	"  -200,  5%"
    xprintf("%-6u", 100);			"100   "
    xprintf("%ld", 12345678L);		"12345678"
    xprintf("%04x", 0xA3);			"00a3"
    xprintf("%08LX", 0x123ABC);		"00123ABC"
    xprintf("%016b", 0x550F);		"0101010100001111"
    xprintf("%s", "String");		"String"
    xprintf("%-4s", "abc");			"abc "
    xprintf("%4s", "abc");			" abc"
    xprintf("%c", 'a');				"a"
    xprintf("%f", 10.0);            <xprintf lacks floating point support>
*/

static 
void vprintf (
	const char*	fmt,	/* Pointer to the format string */
	va_list arp			/* Pointer to arguments */
)
{
	unsigned int r, i, j, w, f;
	unsigned long v;
	char s[16], c, d, *p;


	for (;;) {
		c = *fmt++;					/* Get a char */
		if (!c) break;				/* End of format? */
		if (c != '%') {				/* Pass through it if not a % sequense */
			putchar(c); continue;
		}
		f = 0;
		c = *fmt++;					/* Get first char of the sequense */
		if (c == '0') {				/* Flag: '0' padded */
			f = 1; c = *fmt++;
		} else {
			if (c == '-') {			/* Flag: left justified */
				f = 2; c = *fmt++;
			}
		}
		for (w = 0; c >= '0' && c <= '9'; c = *fmt++)	/* Minimum width */
			w = w * 10 + c - '0';
		if (c == 'l' || c == 'L') {	/* Prefix: Size is long int */
			f |= 4; c = *fmt++;
		}
		if (!c) break;				/* End of format? */
		d = c;
		if (d >= 'a') d -= 0x20;
		switch (d) {				/* Type is... */
		case 'S' :					/* String */
		case 's' :
			p = va_arg(arp, char*);
			for (j = 0; p[j]; j++) ;
			while (!(f & 2) && j++ < w) putchar(' ');
			puts((unsigned char *)p);
			while (j++ < w) putchar(' ');
			continue;
		case 'C' :					/* Character */
		case 'c' :
			putchar((char)va_arg(arp, int)); continue;
		case 'B' :					/* Binary */
		case 'b' :
			r = 2; break;
		case 'O' :					/* Octal */
		case 'o' :
			r = 8; break;
		case 'D' :					/* Signed decimal */
		case 'd' :
		case 'U' :					/* Unsigned decimal */
		case 'u' :
			r = 10; break;
		case 'X' :					/* Hexdecimal */
		case 'x' :
			r = 16; break;
		default:					/* Unknown type (passthrough) */
			putchar(c); continue;
		}

		/* Get an argument and put it in numeral */
		v = (f & 4) ? va_arg(arp, long) : ((d == 'D') ? (long)va_arg(arp, int) : (long)va_arg(arp, unsigned int));
		if ((d == 'D') && (v & 0x80000000)) {
			v = 0 - v;
			f |= 8;
		}
		i = 0;
		do {
			d = (char)(v % r); v /= r;
			if (d > 9) d += (c == 'x') ? 0x27 : 0x07;
			s[i++] = d + '0';
		} while (v && i < sizeof(s));
		if (f & 8) s[i++] = '-';
		j = i; d = (f & 1) ? '0' : ' ';
		while (!(f & 2) && j++ < w) putchar(d);
		do putchar(s[--i]); while(i);
		while (j++ < w) putchar(' ');
	}
}

void sprintf (			/* Put a formatted string to the memory */
	char* buff,			/* Pointer to the output buffer */
	const char*	fmt,	/* Pointer to the format string */
	...					/* Optional arguments */
)
{
	va_list arp;


	outptr = buff;		/* Switch destination for memory */

	va_start(arp, fmt);
	vprintf(fmt, arp);
	va_end(arp);

	*outptr = 0;		/* Terminate output string with a \0 */
	outptr = 0;			/* Switch destination for device */
}


void fprintf (					/* Put a formatted string to the specified device */
	void(*func)(unsigned char),	/* Pointer to the output function */
	const char*	fmt,			/* Pointer to the format string */
	...							/* Optional arguments */
)
{
	va_list arp;
	void (*pf)(unsigned char);


	pf = xfunc_out;		/* Save current output device */
	xfunc_out = func;	/* Switch output to specified device */

	va_start(arp, fmt);
	vprintf(fmt, arp);
	va_end(arp);

	xfunc_out = pf;		/* Restore output device */
}


/*--------------------------------------------------------------------------*/
void put_dump (
	const void* buff,		/* Pointer to the array to be dumped */
	unsigned long addr,		/* Heading address value */
	int len,				/* Number of items to be dumped */
	int width				/* Size of the items (DW_CHAR, DW_SHORT, DW_LONG) */
)
{
	int i;
	const unsigned char *bp;
	const unsigned short *sp;
	const unsigned long *lp;


	printf("%08lX ", addr);		/* address */

	switch (width) {
	case DW_CHAR:
		bp = buff;
		for (i = 0; i < len; i++)		/* Hexdecimal dump */
			printf(" %02X", bp[i]);
		putchar(' ');
		for (i = 0; i < len; i++)		/* ASCII dump */
			putchar((bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.');
		break;
	case DW_SHORT:
		sp = buff;
		do								/* Hexdecimal dump */
			printf(" %04X", *sp++);
		while (--len);
		break;
	case DW_LONG:
		lp = buff;
		do								/* Hexdecimal dump */
			printf(" %08LX", *lp++);
		while (--len);
		break;
	}

	putchar('\n');
}

/* **************************************************************
 *																*
 *	myprintf: This function is used to formating output. 					*
 *  																*
*************************************************************** */
void printf(const char *format, ...)
{
	va_list ap;

	va_start(ap, format);

	vprintf(format, ap);

	va_end(ap);
}

